// 数据类型映射

package dialect

// DataTypeMappingMap 数据库类型映射 mysql/java/varchar
var DataTypeMappingMap = map[string]map[string]map[string]*DataTypeMapping{}

// DataTypeMapping 数据库类型映射
type DataTypeMapping struct {
	Dialect      string // 方言 mysql、postgres、sqlite
	Lang         string // 编程语言 java、go、nodejs
	DbDataType   string // 数据库类型 varchar、int、bigint、datetime、date、timestamp、text、longtext、decimal、double、float
	LangDataType string // 语言类型 java:String、go:string
	LangPackage  string // 语言包 java:java.util.Date、go:time
}

// NewDataTypeMapping 新建数据类型映射
func NewDataTypeMapping(dialect, lang, dbDataType, langDataType, langPackage string) *DataTypeMapping {
	return &DataTypeMapping{
		Dialect:      dialect,
		Lang:         lang,
		DbDataType:   dbDataType,
		LangDataType: langDataType,
		LangPackage:  langPackage,
	}
}

// Clone NewDataTypeMapping 克隆
func (dtm *DataTypeMapping) Clone() *DataTypeMapping {
	return &DataTypeMapping{
		Dialect:      dtm.Dialect,
		Lang:         dtm.Lang,
		DbDataType:   dtm.DbDataType,
		LangDataType: dtm.LangDataType,
		LangPackage:  dtm.LangPackage,
	}
}

// RegisterDataTypeMapping 注册新的数据映射
func RegisterDataTypeMapping(dialect, lang, dbDataType, langDataType, langPackage string) {
	mm, ok := DataTypeMappingMap[dialect]
	if !ok {
		mm = map[string]map[string]*DataTypeMapping{}
		DataTypeMappingMap[dialect] = mm
	}

	m, ok := mm[lang]
	if !ok {
		m = map[string]*DataTypeMapping{}
		mm[lang] = m
	}

	m[dbDataType] = NewDataTypeMapping(dialect, lang, dbDataType, langDataType, langPackage)
}

// GetDataTypeMapping 获取数据类型映射
func GetDataTypeMapping(dialect, langType, dbDataType string) *DataTypeMapping {
	dialectMap, ok := DataTypeMappingMap[dialect]
	if !ok {
		return nil
	}

	langMap, ok := dialectMap[langType]
	if !ok {
		return nil
	}

	dataTypeMapping, ok := langMap[dbDataType]
	if !ok {
		return nil
	}

	return dataTypeMapping
}

// GetLangDataType 获取语言数据类型
func GetLangDataType(dialect, lang, dbDataType string) string {
	dtm := GetDataTypeMapping(dialect, lang, dbDataType)
	if dtm != nil {
		return dtm.LangDataType
	}
	return ""
}

// RegisterDialectDataTypeMapping 注册方言数据类型映射 mysql/java/varchar dialect/lang/dbDataType
// dialect: 方言 mysql、postgres、sqlite
// f: 获取数据类型映射的函数
// ff: 修改数据类型映射的函数
func RegisterDialectDataTypeMapping(dialect string, f func() map[string]*DataTypeMapping, ff func(map[string]*DataTypeMapping)) {
	dialectMap, ok := DataTypeMappingMap[dialect]
	if !ok {
		dialectMap = map[string]map[string]*DataTypeMapping{}
		DataTypeMappingMap[dialect] = dialectMap
	}

	dataTypeMap := f()
	if ff != nil {
		ff(dataTypeMap)
	}

	// 修改dialect
	for _, mapping := range dataTypeMap {
		mapping.Dialect = dialect
		langMap, ok := dialectMap[mapping.Lang]
		if !ok {
			langMap = map[string]*DataTypeMapping{}
			dialectMap[mapping.Lang] = langMap
		}
		langMap[mapping.DbDataType] = mapping
	}
}

// GetJavaCommonDataTypeMapping 获取通用的java数据类型映射
func GetJavaCommonDataTypeMapping() map[string]*DataTypeMapping {
	mmm := map[string]*DataTypeMapping{}

	// 数字
	mmm["integer"] = NewDataTypeMapping(DialectDefault, LangJava, "integer", "Integer", "")
	mmm["real"] = NewDataTypeMapping(DialectDefault, LangJava, "real", "Double", "")
	mmm["numeric"] = NewDataTypeMapping(DialectDefault, LangJava, "numeric", "Double", "")
	mmm["int"] = NewDataTypeMapping(DialectDefault, LangJava, "int", "Integer", "")
	mmm["tinyint"] = NewDataTypeMapping(DialectDefault, LangJava, "tinyint", "Integer", "")
	mmm["smallint"] = NewDataTypeMapping(DialectDefault, LangJava, "smallint", "Integer", "")
	mmm["bigint"] = NewDataTypeMapping(DialectDefault, LangJava, "bigint", "Long", "")
	mmm["decimal"] = NewDataTypeMapping(DialectDefault, LangJava, "decimal", "BigDecimal", "java.math.BigDecimal")
	mmm["float"] = NewDataTypeMapping(DialectDefault, LangJava, "float", "Float", "")
	mmm["double"] = NewDataTypeMapping(DialectDefault, LangJava, "double", "Double", "")
	mmm["bit"] = NewDataTypeMapping(DialectDefault, LangJava, "bit", "Boolean", "")

	// 字符串
	mmm["char"] = NewDataTypeMapping(DialectDefault, LangJava, "char", "String", "")
	mmm["varchar"] = NewDataTypeMapping(DialectDefault, LangJava, "varchar", "String", "")
	mmm["text"] = NewDataTypeMapping(DialectDefault, LangJava, "text", "String", "")
	mmm["tinytext"] = NewDataTypeMapping(DialectDefault, LangJava, "tinytext", "String", "")
	mmm["mediumtext"] = NewDataTypeMapping(DialectDefault, LangJava, "mediumtext", "String", "")
	mmm["longtext"] = NewDataTypeMapping(DialectDefault, LangJava, "longtext", "String", "")
	mmm["json"] = NewDataTypeMapping(DialectDefault, LangJava, "json", "String", "")

	// 日期
	mmm["date"] = NewDataTypeMapping(DialectDefault, LangJava, "date", "Date", "java.util.Date")
	mmm["time"] = NewDataTypeMapping(DialectDefault, LangJava, "time", "Date", "java.util.Date")
	mmm["year"] = NewDataTypeMapping(DialectDefault, LangJava, "year", "Date", "java.util.Date")
	mmm["datetime"] = NewDataTypeMapping(DialectDefault, LangJava, "datetime", "Date", "java.util.Date")
	mmm["timestamp"] = NewDataTypeMapping(DialectDefault, LangJava, "timestamp", "Date", "java.util.Date")

	// 二进制
	mmm["binary"] = NewDataTypeMapping(DialectDefault, LangJava, "binary", "byte[]", "")
	mmm["varbinary"] = NewDataTypeMapping(DialectDefault, LangJava, "varbinary", "byte[]", "")
	mmm["blob"] = NewDataTypeMapping(DialectDefault, LangJava, "blob", "byte[]", "")
	mmm["tinyblob"] = NewDataTypeMapping(DialectDefault, LangJava, "tinyblob", "byte[]", "")
	mmm["mediumblob"] = NewDataTypeMapping(DialectDefault, LangJava, "mediumblob", "byte[]", "")
	mmm["longblob"] = NewDataTypeMapping(DialectDefault, LangJava, "longblob", "byte[]", "")

	// 其他
	mmm["set"] = NewDataTypeMapping(DialectDefault, LangJava, "set", "String", "")
	mmm["geometry"] = NewDataTypeMapping(DialectDefault, LangJava, "geometry", "String", "")
	mmm["enum"] = NewDataTypeMapping(DialectDefault, LangJava, "enum", "String", "")
	mmm["point"] = NewDataTypeMapping(DialectDefault, LangJava, "point", "String", "")
	mmm["linestring"] = NewDataTypeMapping(DialectDefault, LangJava, "linestring", "String", "")
	mmm["polygon"] = NewDataTypeMapping(DialectDefault, LangJava, "polygon", "String", "")
	mmm["multipoint"] = NewDataTypeMapping(DialectDefault, LangJava, "multipoint", "String", "")
	mmm["multilinestring"] = NewDataTypeMapping(DialectDefault, LangJava, "multilinestring", "String", "")
	mmm["multipolygon"] = NewDataTypeMapping(DialectDefault, LangJava, "multipolygon", "String", "")
	mmm["geometrycollection"] = NewDataTypeMapping(DialectDefault, LangJava, "geometrycollection", "String", "")

	return mmm
}

// GetGolangCommonDataTypeMapping 获取通用的go数据类型映射
func GetGolangCommonDataTypeMapping() map[string]*DataTypeMapping {
	mmm := map[string]*DataTypeMapping{}

	// 数字
	mmm["integer"] = NewDataTypeMapping(DialectDefault, LangGo, "integer", "int", "")
	mmm["real"] = NewDataTypeMapping(DialectDefault, LangGo, "real", "float64", "")
	mmm["numeric"] = NewDataTypeMapping(DialectDefault, LangGo, "numeric", "float64", "")

	mmm["int"] = NewDataTypeMapping(DialectDefault, LangGo, "int", "int", "")
	mmm["tinyint"] = NewDataTypeMapping(DialectDefault, LangGo, "tinyint", "int", "")
	mmm["smallint"] = NewDataTypeMapping(DialectDefault, LangGo, "smallint", "int", "")
	mmm["bigint"] = NewDataTypeMapping(DialectDefault, LangGo, "bigint", "int64", "")
	mmm["decimal"] = NewDataTypeMapping(DialectDefault, LangGo, "decimal", "float64", "")
	mmm["float"] = NewDataTypeMapping(DialectDefault, LangGo, "float", "float64", "")
	mmm["double"] = NewDataTypeMapping(DialectDefault, LangGo, "double", "float64", "")
	mmm["bit"] = NewDataTypeMapping(DialectDefault, LangGo, "bit", "bool", "")

	// 字符串
	mmm["char"] = NewDataTypeMapping(DialectDefault, LangGo, "char", "string", "")
	mmm["varchar"] = NewDataTypeMapping(DialectDefault, LangGo, "varchar", "string", "")
	mmm["text"] = NewDataTypeMapping(DialectDefault, LangGo, "text", "string", "")
	mmm["tinytext"] = NewDataTypeMapping(DialectDefault, LangGo, "tinytext", "string", "")
	mmm["mediumtext"] = NewDataTypeMapping(DialectDefault, LangGo, "mediumtext", "string", "")
	mmm["longtext"] = NewDataTypeMapping(DialectDefault, LangGo, "longtext", "string", "")
	mmm["json"] = NewDataTypeMapping(DialectDefault, LangGo, "json", "string", "")

	// 日期
	mmm["date"] = NewDataTypeMapping(DialectDefault, LangGo, "date", "time.Time", "time")
	mmm["time"] = NewDataTypeMapping(DialectDefault, LangGo, "time", "time.Time", "time")
	mmm["year"] = NewDataTypeMapping(DialectDefault, LangGo, "year", "time.Time", "time")
	mmm["datetime"] = NewDataTypeMapping(DialectDefault, LangGo, "datetime", "time.Time", "")
	mmm["timestamp"] = NewDataTypeMapping(DialectDefault, LangGo, "timestamp", "time.Time", "time")

	// 二进制
	mmm["binary"] = NewDataTypeMapping(DialectDefault, LangGo, "binary", "[]byte", "")
	mmm["varbinary"] = NewDataTypeMapping(DialectDefault, LangGo, "varbinary", "[]byte", "")
	mmm["blob"] = NewDataTypeMapping(DialectDefault, LangGo, "blob", "[]byte", "")
	mmm["tinyblob"] = NewDataTypeMapping(DialectDefault, LangGo, "tinyblob", "[]byte", "")
	mmm["mediumblob"] = NewDataTypeMapping(DialectDefault, LangGo, "mediumblob", "[]byte", "")
	mmm["longblob"] = NewDataTypeMapping(DialectDefault, LangGo, "longblob", "[]byte", "")

	// 其他
	mmm["enum"] = NewDataTypeMapping(DialectDefault, LangGo, "enum", "string", "")
	mmm["set"] = NewDataTypeMapping(DialectDefault, LangGo, "set", "string", "")
	mmm["geometry"] = NewDataTypeMapping(DialectDefault, LangGo, "geometry", "string", "")
	mmm["point"] = NewDataTypeMapping(DialectDefault, LangGo, "point", "string", "")
	mmm["linestring"] = NewDataTypeMapping(DialectDefault, LangGo, "linestring", "string", "")
	mmm["polygon"] = NewDataTypeMapping(DialectDefault, LangGo, "polygon", "string", "")
	mmm["multipoint"] = NewDataTypeMapping(DialectDefault, LangGo, "multipoint", "string", "")
	mmm["multilinestring"] = NewDataTypeMapping(DialectDefault, LangGo, "multilinestring", "string", "")
	mmm["multipolygon"] = NewDataTypeMapping(DialectDefault, LangGo, "multipolygon", "string", "")
	mmm["geometrycollection"] = NewDataTypeMapping(DialectDefault, LangGo, "geometrycollection", "string", "")

	return mmm
}

// GetJavaJdbcType 数据库类型到java jdbc类型的映射
func GetJavaJdbcType() map[string]interface{} {

	jdbcTypeMap := map[string]interface{}{}
	jdbcTypeMap["integer"] = "INTEGER"
	jdbcTypeMap["real"] = "REAL"
	jdbcTypeMap["numeric"] = "NUMERIC"
	jdbcTypeMap["int"] = "INTEGER"
	jdbcTypeMap["tinyint"] = "TINYINT"
	jdbcTypeMap["smallint"] = "SMALLINT"
	jdbcTypeMap["bigint"] = "BIGINT"
	jdbcTypeMap["decimal"] = "DECIMAL"
	jdbcTypeMap["float"] = "FLOAT"
	jdbcTypeMap["double"] = "DOUBLE"
	jdbcTypeMap["bit"] = "BIT"
	jdbcTypeMap["char"] = "CHAR"
	jdbcTypeMap["varchar"] = "VARCHAR"
	jdbcTypeMap["text"] = "LONGVARCHAR"
	jdbcTypeMap["tinytext"] = "VARCHAR"
	jdbcTypeMap["mediumtext"] = "VARCHAR"
	jdbcTypeMap["longtext"] = "LONGVARCHAR"
	jdbcTypeMap["json"] = "LONGVARCHAR"
	jdbcTypeMap["date"] = "DATE"
	jdbcTypeMap["time"] = "TIME"
	jdbcTypeMap["year"] = "DATE"
	jdbcTypeMap["datetime"] = "TIMESTAMP"
	jdbcTypeMap["timestamp"] = "TIMESTAMP"
	jdbcTypeMap["binary"] = "BINARY"
	jdbcTypeMap["varbinary"] = "VARBINARY"
	jdbcTypeMap["blob"] = "LONGVARBINARY"
	jdbcTypeMap["tinyblob"] = "VARBINARY"
	jdbcTypeMap["mediumblob"] = "VARBINARY"
	jdbcTypeMap["longblob"] = "LONGVARBINARY"
	jdbcTypeMap["enum"] = "VARCHAR"
	jdbcTypeMap["set"] = "VARCHAR"
	jdbcTypeMap["geometry"] = "VARCHAR"
	jdbcTypeMap["point"] = "VARCHAR"
	jdbcTypeMap["linestring"] = "VARCHAR"
	jdbcTypeMap["polygon"] = "VARCHAR"
	jdbcTypeMap["multipoint"] = "VARCHAR"
	jdbcTypeMap["multilinestring"] = "VARCHAR"
	jdbcTypeMap["multipolygon"] = "VARCHAR"
	jdbcTypeMap["geometrycollection"] = "VARCHAR"

	return jdbcTypeMap

}
